import {ethers} from 'ethers';
import {
  BcosCall,
  BcosGetBlockNumber,
  BcosSendTx,
} from '../../request/api';
import {DataUtils} from './util/devutils/data_utils';
import {TxUtils} from './util/devutils/tx_utils';
import {bcostars} from './util/tars/TransactionTars';

const redPackABI = require('./sol/RedPack.abi.json');
const bac20ABI = require('./sol/IBAC20.abi.json');

var redPackAbiInterface = new ethers.utils.Interface(redPackABI);
var bac20AbiInterface = new ethers.utils.Interface(bac20ABI);

export const approve = async (
  fromAddress,
  privateKey,
  assetAddress,
  redPackAddress,
  amount,
  assert,
) => {
  // console.log('approve params: ', assetAddress, cardManagerAddress, amount)
  // encode function
  const functionData = ibac20ABIInterface.encodeFunctionData('approve', [
    redPackAddress,
    ethers.utils.parseUnits(amount, 0),
  ]);
  // build transaction
  const txData = await buildTransaction(assert, assetAddress, functionData);
  // transaction sign
  const signedTxData = signTransaction(txData, privateKey);
  // send transaction
  const sendRequest = {
    signedTransactionData: signedTxData,
    network: assert.networkName,
    address: fromAddress,
  };
  const receipt = await BcosSendTx(sendRequest);
  // console.log('approve receipt', receipt)
  // retrun transaction receipt
  return receipt;
};


export const sendTX = async (
  fromAddress,
  signedTxData,
  assert,
) => {
  // send transaction
  const sendRequest = {
    signedTransactionData: signedTxData,
    network: assert.networkName,
    address: fromAddress,
  };
  const receipt = await BcosSendTx(sendRequest);
  // console.log('send receipt', receipt)
  // retrun transaction receipt
  return receipt;
};

export const depositRedPackBuildTx = async (
  userAddress, //红包账户地址
  privateKey,
  redPackAddress,
  amount,
  assert,
) => {
  // encode function
  const functionData = redPackAbiInterface.encodeFunctionData('deposit', [
    userAddress,
    ethers.utils.parseUnits(amount, 0),
  ]);
  // build transaction
  const txData = await buildTransaction(assert, redPackAddress, functionData);
  // transaction sign
  const signedTxData = signTransaction(txData, privateKey);
  return signedTxData;
};


export const TransferBcosERC20 = async (
  fromAddress,
  privateKey,
  assetAddress,
  toAddress,
  amount,
  asset,
) => {
  // encode function
  const functionData = bac20AbiInterface.encodeFunctionData('send', [
    toAddress,
    //special handler
    ethers.utils.parseUnits(amount, 0),
  ]);
  // build transaction
  const txData = await buildTransaction(asset, assetAddress, functionData);
  // transaction sign
  const signedTxData = signTransaction(txData, privateKey);
  // send transaction
  const sendRequest = {
    signedTransactionData: signedTxData,
    network: asset.networkName,
    address: fromAddress,
  };
  const receipt = await BcosSendTx(sendRequest);
  // console.log("Transfer receipt is", receipt);
  // retrun transaction receipt
  return receipt;
};

const ibac20ABI = require('./sol/IBAC20.abi.json');
var ibac20ABIInterface = new ethers.utils.Interface(ibac20ABI);

export const ExchangeCard = async (
  fromAddress,
  privateKey,
  assetAddress,
  cardManagerAddress,
  amount,
  assert,
) => {
  const approveReceipt = await send(
    fromAddress,
    privateKey,
    assetAddress,
    cardManagerAddress,
    amount,
    assert,
  );
  return approveReceipt;
};

const send = async (
  fromAddress,
  privateKey,
  assetAddress,
  cardManagerAddress,
  amount,
  assert,
) => {
  // console.log('send params: ', assetAddress, cardManagerAddress, amount)
  // encode function
  const functionData = ibac20ABIInterface.encodeFunctionData('send', [
    cardManagerAddress,
    ethers.utils.parseUnits(amount, 0),
  ]);
  // build transaction
  const txData = await buildTransaction(assert, assetAddress, functionData);
  // transaction sign
  const signedTxData = signTransaction(txData, privateKey);
  // send transaction
  const sendRequest = {
    signedTransactionData: signedTxData,
    network: assert.networkName,
    address: fromAddress,
  };
  const receipt = await BcosSendTx(sendRequest);
  // console.log('send receipt', receipt)
  // retrun transaction receipt
  return receipt;
};

export const buildTransaction = async (assert, assetAddress, functionData) => {
  const getBlockNumberRequest = {
    network: assert.networkName,
  };
  let blockNumber = await BcosGetBlockNumber(getBlockNumberRequest);
  // console.log('blockNumber: ', blockNumber);
  let txData = new bcostars.TransactionData();
  // console.log(">> chainId",assert.assetConfig.chainID )
  txData.version = 0;
  txData.chainID = assert.assetConfig.chainID;
  txData.groupID = assert.assetConfig.groupID;
  txData.to = assetAddress;
  txData.blockLimit = blockNumber.data + 1000;
  txData.nonce = DataUtils.bigIntRandom().toString(); //nonce是一个整形数的字符串
  TxUtils.set_txdata_input(txData, functionData);

  return txData;
};

export const signTransaction = (txData, privateKey) => {
  let signedTransactionData = TxUtils.build_rawtransaction_by_txdata(
    txData,
    privateKey,
  );
  let signedTxData = ethers.utils.hexlify(signedTransactionData);
  return signedTxData;
};

export const redPackBalance = async (
  userAddress, //红包账户地址
  redPackAddress,
) => {
  const functionData = redPackAbiInterface.encodeFunctionData('balance', [
    userAddress,
  ]);
  const callRequest = {
    from: userAddress,
    to: redPackAddress,
    data: functionData,
    network: 'main',
  };
  console.log('redpack balance request is', callRequest);
  const result = await BcosCall(callRequest);
  console.log('redpack balance response is', result);
  if (result?.code !== 0 || result.data?.status !== 0) {
    throw new Error('获取红包账户余额异常');
  }
  return result;
};



export const buildTx = async (
  privateKey,
  assetAddress,
  cardManagerAddress,
  amount,
  assert,
) => {
  console.log('send params: ', assetAddress, cardManagerAddress, amount)
  // encode function
  const functionData = ibac20ABIInterface.encodeFunctionData('send', [
    cardManagerAddress,
    ethers.utils.parseUnits(amount, 0),
  ]);
  // build transaction
  const txData = await buildTransaction(assert, assetAddress, functionData);
  // transaction sign
  const signedTxData = signTransaction(txData, privateKey);

  return signedTxData;

};

